package com.codeest.geeknews.media.music;///*
// * Copyright (C) 2007 The Android Open Source Project
// *
// * Licensed under the Apache License, Version 2.0 (the "License");
// * you may not use this file except in compliance with the License.
// * You may obtain a copy of the License at
// *
// *      http://www.apache.org/licenses/LICENSE-2.0
// *
// * Unless required by applicable law or agreed to in writing, software
// * distributed under the License is distributed on an "AS IS" BASIS,
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// * See the License for the specific language governing permissions and
// * limitations under the License.
// */
//
//package com.songu.recordvoice.music;
//
//import android.app.Notification;
//import android.app.PendingIntent;
//import android.app.Service;
//import android.appwidget.AppWidgetManager;
//import android.content.BroadcastReceiver;
//import android.content.ComponentName;
//import android.content.ContentResolver;
//import android.content.Context;
//import android.content.Intent;
//import android.content.IntentFilter;
//import android.content.SharedPreferences;
//import android.content.SharedPreferences.Editor;
//import android.database.Cursor;
//import android.media.AudioManager;
//import android.media.AudioManager.OnAudioFocusChangeListener;
//import android.media.RemoteControlClient;
//import android.media.audiofx.AudioEffect;
//import android.net.Uri;
//import android.os.Handler;
//import android.os.IBinder;
//import android.os.Message;
//import android.os.PowerManager;
//import android.os.PowerManager.WakeLock;
//import android.os.SystemClock;
//import android.provider.MediaStore;
//import android.support.v4.content.SharedPreferencesCompat;
//import android.util.Log;
//import android.widget.RemoteViews;
//import android.widget.Toast;
//
//import com.samsung.sample.jspeex.R;
//import com.songu.recordvoice.receiver.MediaButtonIntentReceiver;
//
//import java.util.Vector;
//
///**
// * 谷歌源码
// * Provides "background" audio playback capabilities, allowing the
// * user to switch between activities without stopping playback.
// */
//public class MediaPlaybackService extends Service {
//    /**
//     * used to specify whether enqueue() should start playing
//     * the new list of files right away, next or once all the currently
//     * queued files have been played
//     */
//    public static final int NOW = 1;
//    public static final int NEXT = 2;
//    public static final int LAST = 3;
//    public static final int PLAYBACKSERVICE_STATUS = 1;
//
//    public static final int SHUFFLE_NONE = 0;
//    public static final int SHUFFLE_NORMAL = 1;
//    public static final int SHUFFLE_AUTO = 2;
//
//    public static final int REPEAT_NONE = 0;
//    public static final int REPEAT_CURRENT = 1;
//    public static final int REPEAT_ALL = 2;
//
//    public static final String PLAYSTATE_CHANGED = "com.android.music.playstatechanged";
//    public static final String META_CHANGED = "com.android.music.metachanged";
//    public static final String QUEUE_CHANGED = "com.android.music.queuechanged";
//
//    public static final String SERVICECMD = "com.android.music.musicservicecommand";
//    public static final String CMDNAME = "command";
//    public static final String CMDTOGGLEPAUSE = "togglepause";
//    public static final String CMDSTOP = "stop";
//    public static final String CMDPAUSE = "pause";
//    public static final String CMDPLAY = "play";
//    public static final String CMDPREVIOUS = "previous";
//    public static final String CMDNEXT = "next";
//
//    public static final String TOGGLEPAUSE_ACTION = "com.android.music.musicservicecommand.togglepause";
//    public static final String PAUSE_ACTION = "com.android.music.musicservicecommand.pause";
//    public static final String PREVIOUS_ACTION = "com.android.music.musicservicecommand.previous";
//    public static final String NEXT_ACTION = "com.android.music.musicservicecommand.next";
//
//    private static final int TRACK_ENDED = 1;
//    private static final int RELEASE_WAKELOCK = 2;
//    private static final int SERVER_DIED = 3;
//    private static final int FOCUSCHANGE = 4;
//    private static final int FADEDOWN = 5;
//    private static final int FADEUP = 6;
//    private static final int TRACK_WENT_TO_NEXT = 7;
//    private static final int MAX_HISTORY_SIZE = 100;
//
//    private MultiPlayer mPlayer;
//    private String mFileToPlay;
//    private int mShuffleMode = SHUFFLE_NONE;
//    private int mRepeatMode = REPEAT_NONE;
//    private int mMediaMountedCount = 0;
//    private long[] mAutoShuffleList = null;
//    private long[] mPlayList = null;
//    private int mPlayListLen = 0;
//    private Vector<Integer> mHistory = new Vector<Integer>(MAX_HISTORY_SIZE);
//    private Cursor mCursor;
//    private int mPlayPos = -1;
//    private int mNextPlayPos = -1;
//    private static final String LOGTAG = "MediaPlaybackService";
//    private final Shuffler mRand = new Shuffler();
//    private int mOpenFailedCounter = 0;
//    String[] mCursorCols = new String[]{
//            "audio._id AS _id",             // index must match IDCOLIDX below
//            MediaStore.Audio.Media.ARTIST,
//            MediaStore.Audio.Media.ALBUM,
//            MediaStore.Audio.Media.TITLE,
//            MediaStore.Audio.Media.DATA,
//            MediaStore.Audio.Media.MIME_TYPE,
//            MediaStore.Audio.Media.ALBUM_ID,
//            MediaStore.Audio.Media.ARTIST_ID,
//            MediaStore.Audio.Media.IS_PODCAST, // index must match PODCASTCOLIDX below
//            MediaStore.Audio.Media.BOOKMARK    // index must match BOOKMARKCOLIDX below
//    };
//    private final static int IDCOLIDX = 0;
//    private final static int PODCASTCOLIDX = 8;
//    private final static int BOOKMARKCOLIDX = 9;
//    private BroadcastReceiver mUnmountReceiver = null;
//    private WakeLock mWakeLock;
//    private int mServiceStartId = -1;
//    private boolean mServiceInUse = false;
//    private boolean mIsSupposedToBePlaying = false;
//    private boolean mQuietMode = false;
//    private AudioManager mAudioManager;
//    private boolean mQueueIsSaveable = true;
//    // used to track what type of audio focus loss caused the playback to pause
//    private boolean mPausedByTransientLossOfFocus = false;
//
//    private SharedPreferences mPreferences;
//    // We use this to distinguish between different cards when saving/restoring playlists.
//    // This will have to change if we want to support multiple simultaneous cards.
//    private int mCardId;
//
//    private MediaAppWidgetProvider mAppWidgetProvider = MediaAppWidgetProvider.getInstance();
//
//    // interval after which we stop the service when idle
//    private static final int IDLE_DELAY = 60000;
//
//    private RemoteControlClient mRemoteControlClient;
//
//    private Handler mMediaplayerHandler = new Handler() {
//        float mCurrentVolume = 1.0f;
//
//        @Override
//        public void handleMessage(Message msg) {
//            MusicUtils.debugLog("mMediaplayerHandler.handleMessage " + msg.what);
//            switch (msg.what) {
//                case FADEDOWN:
//                    mCurrentVolume -= .05f;
//                    if (mCurrentVolume > .2f) {
//                        mMediaplayerHandler.sendEmptyMessageDelayed(FADEDOWN, 10);
//                    } else {
//                        mCurrentVolume = .2f;
//                    }
//                    mPlayer.setVolume(mCurrentVolume);
//                    break;
//                case FADEUP:
//                    mCurrentVolume += .01f;
//                    if (mCurrentVolume < 1.0f) {
//                        mMediaplayerHandler.sendEmptyMessageDelayed(FADEUP, 10);
//                    } else {
//                        mCurrentVolume = 1.0f;
//                    }
//                    mPlayer.setVolume(mCurrentVolume);
//                    break;
//                case SERVER_DIED:
//                    if (mIsSupposedToBePlaying) {
//                        gotoNext(true);
//                    } else {
//                        // the server died when we were idle, so just
//                        // reopen the same song (it will start again
//                        // from the beginning though when the user
//                        // restarts)
//                        openCurrentAndNext();
//                    }
//                    break;
//                case TRACK_WENT_TO_NEXT:
//                    mPlayPos = mNextPlayPos;
//                    if (mCursor != null) {
//                        mCursor.close();
//                        mCursor = null;
//                    }
//                    mCursor = getCursorForId(mPlayList[mPlayPos]);
//                    notifyChange(META_CHANGED);
//                    updateNotification();
//                    setNextTrack();
//                    break;
//                case TRACK_ENDED:
//                    if (mRepeatMode == REPEAT_CURRENT) {
//                        seek(0);
//                        play();
//                    } else {
//                        gotoNext(false);
//                    }
//                    break;
//                case RELEASE_WAKELOCK:
//                    mWakeLock.release();
//                    break;
//
//                case FOCUSCHANGE:
//                    // This code is here so we can better synchronize it with the code that
//                    // handles fade-in
//                    switch (msg.arg1) {
//                        case AudioManager.AUDIOFOCUS_LOSS:
//                            Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_LOSS");
//                            if (isPlaying()) {
//                                mPausedByTransientLossOfFocus = false;
//                            }
//                            pause();
//                            break;
//                        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
//                            mMediaplayerHandler.removeMessages(FADEUP);
//                            mMediaplayerHandler.sendEmptyMessage(FADEDOWN);
//                            break;
//                        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
//                            Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_LOSS_TRANSIENT");
//                            if (isPlaying()) {
//                                mPausedByTransientLossOfFocus = true;
//                            }
//                            pause();
//                            break;
//                        case AudioManager.AUDIOFOCUS_GAIN:
//                            Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_GAIN");
//                            if (!isPlaying() && mPausedByTransientLossOfFocus) {
//                                mPausedByTransientLossOfFocus = false;
//                                mCurrentVolume = 0f;
//                                mPlayer.setVolume(mCurrentVolume);
//                                play(); // also queues a fade-in
//                            } else {
//                                mMediaplayerHandler.removeMessages(FADEDOWN);
//                                mMediaplayerHandler.sendEmptyMessage(FADEUP);
//                            }
//                            break;
//                        default:
//                            Log.e(LOGTAG, "Unknown audio focus change code");
//                    }
//                    break;
//
//                default:
//                    break;
//            }
//        }
//    };
//
//    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
//        @Override
//        public void onReceive(Context context, Intent intent) {
//            String action = intent.getAction();
//            String cmd = intent.getStringExtra("command");
//            MusicUtils.debugLog("mIntentReceiver.onReceive " + action + " / " + cmd);
//            if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) {
//                gotoNext(true);
//            } else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) {
//                prev();
//            } else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) {
//                if (isPlaying()) {
//                    pause();
//                    mPausedByTransientLossOfFocus = false;
//                } else {
//                    play();
//                }
//            } else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) {
//                pause();
//                mPausedByTransientLossOfFocus = false;
//            } else if (CMDPLAY.equals(cmd)) {
//                play();
//            } else if (CMDSTOP.equals(cmd)) {
//                pause();
//                mPausedByTransientLossOfFocus = false;
//                seek(0);
//            } else if (MediaAppWidgetProvider.CMDAPPWIDGETUPDATE.equals(cmd)) {
//                // Someone asked us to refresh a set of specific widgets, probably
//                // because they were just added.
//                int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
//                mAppWidgetProvider.performUpdate(MediaPlaybackService.this, appWidgetIds);
//            }
//        }
//    };
//
//    private OnAudioFocusChangeListener mAudioFocusListener = new OnAudioFocusChangeListener() {
//        public void onAudioFocusChange(int focusChange) {
//            mMediaplayerHandler.obtainMessage(FOCUSCHANGE, focusChange, 0).sendToTarget();
//        }
//    };
//
//    public MediaPlaybackService() {
//    }
//
//    @Override
//    public void onCreate() {
//        super.onCreate();
//
//        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
//        ComponentName rec = new ComponentName(getPackageName(),
//                MediaButtonIntentReceiver.class.getName());
//        mAudioManager.registerMediaButtonEventReceiver(rec);
//        // TODO update to new constructor
////        mRemoteControlClient = new RemoteControlClient(rec);
////        mAudioManager.registerRemoteControlClient(mRemoteControlClient);
////
////        int flags = RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS
////                | RemoteControlClient.FLAG_KEY_MEDIA_NEXT
////                | RemoteControlClient.FLAG_KEY_MEDIA_PLAY
////                | RemoteControlClient.FLAG_KEY_MEDIA_PAUSE
////                | RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE
////                | RemoteControlClient.FLAG_KEY_MEDIA_STOP;
////        mRemoteControlClient.setTransportControlFlags(flags);
//
//        mPreferences = getSharedPreferences("Music", MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE);
//        mCardId = MusicUtils.getCardId(this);
//
//        registerExternalStorageListener();
//
//        // Needs to be done in this thread, since otherwise ApplicationContext.getPowerManager() crashes.
//        mPlayer = new MultiPlayer();
//        mPlayer.setHandler(mMediaplayerHandler);
//
//        reloadQueue();
//        notifyChange(QUEUE_CHANGED);
//        notifyChange(META_CHANGED);
//
//        IntentFilter commandFilter = new IntentFilter();
//        commandFilter.addAction(SERVICECMD);
//        commandFilter.addAction(TOGGLEPAUSE_ACTION);
//        commandFilter.addAction(PAUSE_ACTION);
//        commandFilter.addAction(NEXT_ACTION);
//        commandFilter.addAction(PREVIOUS_ACTION);
//        registerReceiver(mIntentReceiver, commandFilter);
//
//        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
//        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName());
//        mWakeLock.setReferenceCounted(false);
//
//        // If the service was idle, but got killed before it stopped itself, the
//        // system will relaunch it. Make sure it gets stopped again in that case.
//        Message msg = mDelayedStopHandler.obtainMessage();
//        mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
//    }
//
//    @Override
//    public void onDestroy() {
//        // Check that we're not being destroyed while something is still playing.
//        if (isPlaying()) {
//            Log.e(LOGTAG, "Service being destroyed while still playing.");
//        }
//        // release all MediaPlayer resources, including the native player and wakelocks
//        Intent i = new Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
//        i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, getAudioSessionId());
//        i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName());
//        sendBroadcast(i);
//        mPlayer.release();
//        mPlayer = null;
//
//        mAudioManager.abandonAudioFocus(mAudioFocusListener);
//        //mAudioManager.unregisterRemoteControlClient(mRemoteControlClient);
//
//        // make sure there aren't any other messages coming
//        mDelayedStopHandler.removeCallbacksAndMessages(null);
//        mMediaplayerHandler.removeCallbacksAndMessages(null);
//
//        if (mCursor != null) {
//            mCursor.close();
//            mCursor = null;
//        }
//
//        unregisterReceiver(mIntentReceiver);
//        if (mUnmountReceiver != null) {
//            unregisterReceiver(mUnmountReceiver);
//            mUnmountReceiver = null;
//        }
//        mWakeLock.release();
//        super.onDestroy();
//    }
//
//    private final char hexdigits[] = new char[]{
//            '0', '1', '2', '3',
//            '4', '5', '6', '7',
//            '8', '9', 'a', 'b',
//            'c', 'd', 'e', 'f'
//    };
//
//    private void saveQueue(boolean full) {
//        if (!mQueueIsSaveable) {
//            return;
//        }
//
//        Editor ed = mPreferences.edit();
//        //long start = System.currentTimeMillis();
//        if (full) {
//            StringBuilder q = new StringBuilder();
//
//            // The current playlist is saved as a list of "reverse hexadecimal"
//            // numbers, which we can generate faster than normal decimal or
//            // hexadecimal numbers, which in turn allows us to save the playlist
//            // more often without worrying too much about performance.
//            // (saving the full state takes about 40 ms under no-load conditions
//            // on the phone)
//            int len = mPlayListLen;
//            for (int i = 0; i < len; i++) {
//                long n = mPlayList[i];
//                if (n < 0) {
//                    continue;
//                } else if (n == 0) {
//                    q.append("0;");
//                } else {
//                    while (n != 0) {
//                        int digit = (int) (n & 0xf);
//                        n >>>= 4;
//                        q.append(hexdigits[digit]);
//                    }
//                    q.append(";");
//                }
//            }
//            //Log.i("@@@@ service", "created queue string in " + (System.currentTimeMillis() - start) + " ms");
//            ed.putString("queue", q.toString());
//            ed.putInt("cardid", mCardId);
//            if (mShuffleMode != SHUFFLE_NONE) {
//                // In shuffle mode we need to save the history too
//                len = mHistory.size();
//                q.setLength(0);
//                for (int i = 0; i < len; i++) {
//                    int n = mHistory.get(i);
//                    if (n == 0) {
//                        q.append("0;");
//                    } else {
//                        while (n != 0) {
//                            int digit = (n & 0xf);
//                            n >>>= 4;
//                            q.append(hexdigits[digit]);
//                        }
//                        q.append(";");
//                    }
//                }
//                ed.putString("history", q.toString());
//            }
//        }
//        ed.putInt("curpos", mPlayPos);
//        if (mPlayer.isInitialized()) {
//            ed.putLong("seekpos", mPlayer.position());
//        }
//        ed.putInt("repeatmode", mRepeatMode);
//        ed.putInt("shufflemode", mShuffleMode);
//        SharedPreferencesCompat.apply(ed);
//
//        //Log.i("@@@@ service", "saved state in " + (System.currentTimeMillis() - start) + " ms");
//    }
//
//    private void reloadQueue() {
//        String q = null;
//
//        boolean newstyle = false;
//        int id = mCardId;
//        if (mPreferences.contains("cardid")) {
//            newstyle = true;
//            id = mPreferences.getInt("cardid", ~mCardId);
//        }
//        if (id == mCardId) {
//            // Only restore the saved playlist if the card is still
//            // the same one as when the playlist was saved
//            q = mPreferences.getString("queue", "");
//        }
//        int qlen = q != null ? q.length() : 0;
//        if (qlen > 1) {
//            //Log.i("@@@@ service", "loaded queue: " + q);
//            int plen = 0;
//            int n = 0;
//            int shift = 0;
//            for (int i = 0; i < qlen; i++) {
//                char c = q.charAt(i);
//                if (c == ';') {
//                    ensurePlayListCapacity(plen + 1);
//                    mPlayList[plen] = n;
//                    plen++;
//                    n = 0;
//                    shift = 0;
//                } else {
//                    if (c >= '0' && c <= '9') {
//                        n += ((c - '0') << shift);
//                    } else if (c >= 'a' && c <= 'f') {
//                        n += ((10 + c - 'a') << shift);
//                    } else {
//                        // bogus playlist data
//                        plen = 0;
//                        break;
//                    }
//                    shift += 4;
//                }
//            }
//            mPlayListLen = plen;
//
//            int pos = mPreferences.getInt("curpos", 0);
//            if (pos < 0 || pos >= mPlayListLen) {
//                // The saved playlist is bogus, discard it
//                mPlayListLen = 0;
//                return;
//            }
//            mPlayPos = pos;
//
//            // When reloadQueue is called in response to a card-insertion,
//            // we might not be able to query the media provider right away.
//            // To deal with this, try querying for the current file, and if
//            // that fails, wait a while and try again. If that too fails,
//            // assume there is a problem and don't restore the state.
//            Cursor crsr = MusicUtils.query(this,
//                    MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
//                    new String[]{"_id"}, "_id=" + mPlayList[mPlayPos], null, null);
//            if (crsr == null || crsr.getCount() == 0) {
//                // wait a bit and try again
//                SystemClock.sleep(3000);
//                crsr = getContentResolver().query(
//                        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
//                        mCursorCols, "_id=" + mPlayList[mPlayPos], null, null);
//            }
//            if (crsr != null) {
//                crsr.close();
//            }
//
//            // Make sure we don't auto-skip to the next song, since that
//            // also starts playback. What could happen in that case is:
//            // - music is paused
//            // - go to UMS and delete some files, including the currently playing one
//            // - come back from UMS
//            // (time passes)
//            // - music app is killed for some reason (out of memory)
//            // - music service is restarted, service restores state, doesn't find
//            //   the "current" file, goes to the next and: playback starts on its
//            //   own, potentially at some random inconvenient time.
//            mOpenFailedCounter = 20;
//            mQuietMode = true;
//            openCurrentAndNext();
//            mQuietMode = false;
//            if (!mPlayer.isInitialized()) {
//                // couldn't restore the saved state
//                mPlayListLen = 0;
//                return;
//            }
//
//            long seekpos = mPreferences.getLong("seekpos", 0);
//            seek(seekpos >= 0 && seekpos < duration() ? seekpos : 0);
//            Log.d(LOGTAG, "restored queue, currently at position "
//                    + position() + "/" + duration()
//                    + " (requested " + seekpos + ")");
//
//            int repmode = mPreferences.getInt("repeatmode", REPEAT_NONE);
//            if (repmode != REPEAT_ALL && repmode != REPEAT_CURRENT) {
//                repmode = REPEAT_NONE;
//            }
//            mRepeatMode = repmode;
//
//            int shufmode = mPreferences.getInt("shufflemode", SHUFFLE_NONE);
//            if (shufmode != SHUFFLE_AUTO && shufmode != SHUFFLE_NORMAL) {
//                shufmode = SHUFFLE_NONE;
//            }
//            if (shufmode != SHUFFLE_NONE) {
//                // in shuffle mode we need to restore the history too
//                q = mPreferences.getString("history", "");
//                qlen = q != null ? q.length() : 0;
//                if (qlen > 1) {
//                    plen = 0;
//                    n = 0;
//                    shift = 0;
//                    mHistory.clear();
//                    for (int i = 0; i < qlen; i++) {
//                        char c = q.charAt(i);
//                        if (c == ';') {
//                            if (n >= mPlayListLen) {
//                                // bogus history data
//                                mHistory.clear();
//                                break;
//                            }
//                            mHistory.add(n);
//                            n = 0;
//                            shift = 0;
//                        } else {
//                            if (c >= '0' && c <= '9') {
//                                n += ((c - '0') << shift);
//                            } else if (c >= 'a' && c <= 'f') {
//                                n += ((10 + c - 'a') << shift);
//                            } else {
//                                // bogus history data
//                                mHistory.clear();
//                                break;
//                            }
//                            shift += 4;
//                        }
//                    }
//                }
//            }
//            if (shufmode == SHUFFLE_AUTO) {
//                if (!makeAutoShuffleList()) {
//                    shufmode = SHUFFLE_NONE;
//                }
//            }
//            mShuffleMode = shufmode;
//        }
//    }
//
//    @Override
//    public IBinder onBind(Intent intent) {
//        mDelayedStopHandler.removeCallbacksAndMessages(null);
//        mServiceInUse = true;
//        return mBinder;
//    }
//
//    @Override
//    public void onRebind(Intent intent) {
//        mDelayedStopHandler.removeCallbacksAndMessages(null);
//        mServiceInUse = true;
//    }
//
//    @Override
//    public int onStartCommand(Intent intent, int flags, int startId) {
//        mServiceStartId = startId;
//        mDelayedStopHandler.removeCallbacksAndMessages(null);
//
//        if (intent != null) {
//            String action = intent.getAction();
//            String cmd = intent.getStringExtra("command");
//            MusicUtils.debugLog("onStartCommand " + action + " / " + cmd);
//
//            if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) {
//                gotoNext(true);
//            } else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) {
//                if (position() < 2000) {
//                    prev();
//                } else {
//                    seek(0);
//                    play();
//                }
//            } else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) {
//                if (isPlaying()) {
//                    pause();
//                    mPausedByTransientLossOfFocus = false;
//                } else {
//                    play();
//                }
//            } else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) {
//                pause();
//                mPausedByTransientLossOfFocus = false;
//            } else if (CMDPLAY.equals(cmd)) {
//                play();
//            } else if (CMDSTOP.equals(cmd)) {
//                pause();
//                mPausedByTransientLossOfFocus = false;
//                seek(0);
//            }
//        }
//
//        // make sure the service will shut down on its own if it was
//        // just started but not bound to and nothing is playing
//        mDelayedStopHandler.removeCallbacksAndMessages(null);
//        Message msg = mDelayedStopHandler.obtainMessage();
//        mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
//        return START_STICKY;
//    }
//
//    @Override
//    public boolean onUnbind(Intent intent) {
//        mServiceInUse = false;
//
//        // Take a snapshot of the current playlist
//        saveQueue(true);
//
//        if (isPlaying() || mPausedByTransientLossOfFocus) {
//            // something is currently playing, or will be playing once
//            // an in-progress action requesting audio focus ends, so don't stop the service now.
//            return true;
//        }
//
//        // If there is a playlist but playback is paused, then wait a while
//        // before stopping the service, so that pause/resume isn't slow.
//        // Also delay stopping the service if we're transitioning between tracks.
//        if (mPlayListLen > 0 || mMediaplayerHandler.hasMessages(TRACK_ENDED)) {
//            Message msg = mDelayedStopHandler.obtainMessage();
//            mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
//            return true;
//        }
//
//        // No active playlist, OK to stop the service right now
//        stopSelf(mServiceStartId);
//        return true;
//    }
//
//    private Handler mDelayedStopHandler = new Handler() {
//        @Override
//        public void handleMessage(Message msg) {
//            // Check again to make sure nothing is playing right now
//            if (isPlaying() || mPausedByTransientLossOfFocus || mServiceInUse
//                    || mMediaplayerHandler.hasMessages(TRACK_ENDED)) {
//                return;
//            }
//            // save the queue again, because it might have changed
//            // since the user exited the music app (because of
//            // party-shuffle or because the play-position changed)
//            saveQueue(true);
//            stopSelf(mServiceStartId);
//        }
//    };
//
//    /**
//     * Called when we receive a ACTION_MEDIA_EJECT notification.
//     *
//     * @param storagePath path to mount point for the removed media
//     */
//    public void closeExternalStorageFiles(String storagePath) {
//        // stop playback and clean up if the SD card is going to be unmounted.
//        stop(true);
//        notifyChange(QUEUE_CHANGED);
//        notifyChange(META_CHANGED);
//    }
//
//    /**
//     * Registers an intent to listen for ACTION_MEDIA_EJECT notifications.
//     * The intent will call closeExternalStorageFiles() if the external media
//     * is going to be ejected, so applications can clean up any files they have open.
//     */
//    public void registerExternalStorageListener() {
//        if (mUnmountReceiver == null) {
//            mUnmountReceiver = new BroadcastReceiver() {
//                @Override
//                public void onReceive(Context context, Intent intent) {
//                    String action = intent.getAction();
//                    if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
//                        saveQueue(true);
//                        mQueueIsSaveable = false;
//                        closeExternalStorageFiles(intent.getData().getPath());
//                    } else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
//                        mMediaMountedCount++;
//                        mCardId = MusicUtils.getCardId(MediaPlaybackService.this);
//                        reloadQueue();
//                        mQueueIsSaveable = true;
//                        notifyChange(QUEUE_CHANGED);
//                        notifyChange(META_CHANGED);
//                    }
//                }
//            };
//            IntentFilter iFilter = new IntentFilter();
//            iFilter.addAction(Intent.ACTION_MEDIA_EJECT);
//            iFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
//            iFilter.addDataScheme("file");
//            registerReceiver(mUnmountReceiver, iFilter);
//        }
//    }
//
//    /**
//     * Notify the change-receivers that something has changed.
//     * The intent that is sent contains the following data
//     * for the currently playing track:
//     * "id" - Integer: the database row ID
//     * "artist" - String: the name of the artist
//     * "album" - String: the name of the album
//     * "track" - String: the name of the track
//     * The intent has an action that is one of
//     * "com.android.music.metachanged"
//     * "com.android.music.queuechanged",
//     * "com.android.music.playbackcomplete"
//     * "com.android.music.playstatechanged"
//     * respectively indicating that a new track has
//     * started playing, that the playback queue has
//     * changed, that playback has stopped because
//     * the last file in the list has been played,
//     * or that the play-state changed (paused/resumed).
//     */
//    private void notifyChange(String what) {
//
//        Intent i = new Intent(what);
//        i.putExtra("id", Long.valueOf(getAudioId()));
//        i.putExtra("artist", getArtistName());
//        i.putExtra("album", getAlbumName());
//        i.putExtra("track", getTrackName());
//        i.putExtra("playing", isPlaying());
//        sendStickyBroadcast(i);
//
//        if (what.equals(PLAYSTATE_CHANGED)) {
////            mRemoteControlClient.setPlaybackState(isPlaying() ?
////                    RemoteControlClient.PLAYSTATE_PLAYING : RemoteControlClient.PLAYSTATE_PAUSED);
//        } else if (what.equals(META_CHANGED)) {
////            RemoteControlClient.MetadataEditor ed = mRemoteControlClient.editMetadata(true);
////            ed.putString(MediaMetadataRetriever.METADATA_KEY_TITLE, getTrackName());
////            ed.putString(MediaMetadataRetriever.METADATA_KEY_ALBUM, getAlbumName());
////            ed.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, getArtistName());
////            ed.putLong(MediaMetadataRetriever.METADATA_KEY_DURATION, duration());
////            Bitmap b = MusicUtils.getArtwork(this, getAudioId(), getAlbumId(), false);
////            if (b != null) {
////                ed.putBitmap(MetadataEditor.BITMAP_KEY_ARTWORK, b);
////            }
////            ed.apply();
//        }
//
//        if (what.equals(QUEUE_CHANGED)) {
//            saveQueue(true);
//        } else {
//            saveQueue(false);
//        }
//
//        // Share this notification directly with our widgets
//        mAppWidgetProvider.notifyChange(this, what);
//    }
//
//    private void ensurePlayListCapacity(int size) {
//        if (mPlayList == null || size > mPlayList.length) {
//            // reallocate at 2x requested size so we don't
//            // need to grow and copy the array for every
//            // insert
//            long[] newlist = new long[size * 2];
//            int len = mPlayList != null ? mPlayList.length : mPlayListLen;
//            for (int i = 0; i < len; i++) {
//                newlist[i] = mPlayList[i];
//            }
//            mPlayList = newlist;
//        }
//        // FIXME: shrink the array when the needed size is much smaller
//        // than the allocated size
//    }
//
//    // insert the list of songs at the specified position in the playlist
//    private void addToPlayList(long[] list, int position) {
//        int addlen = list.length;
//        if (position < 0) { // overwrite
//            mPlayListLen = 0;
//            position = 0;
//        }
//        ensurePlayListCapacity(mPlayListLen + addlen);
//        if (position > mPlayListLen) {
//            position = mPlayListLen;
//        }
//
//        // move part of list after insertion point
//        int tailsize = mPlayListLen - position;
//        for (int i = tailsize; i > 0; i--) {
//            mPlayList[position + i] = mPlayList[position + i - addlen];
//        }
//
//        // copy list into playlist
//        for (int i = 0; i < addlen; i++) {
//            mPlayList[position + i] = list[i];
//        }
//        mPlayListLen += addlen;
//        if (mPlayListLen == 0) {
//            mCursor.close();
//            mCursor = null;
//            notifyChange(META_CHANGED);
//        }
//    }
//
//    /**
//     * Appends a list of tracks to the current playlist.
//     * If nothing is playing currently, playback will be started at
//     * the first track.
//     * If the action is NOW, playback will switch to the first of
//     * the new tracks immediately.
//     *
//     * @param list   The list of tracks to append.
//     * @param action NOW, NEXT or LAST
//     */
//    public void enqueue(long[] list, int action) {
//        synchronized (this) {
//            if (action == NEXT && mPlayPos + 1 < mPlayListLen) {
//                addToPlayList(list, mPlayPos + 1);
//                notifyChange(QUEUE_CHANGED);
//            } else {
//                // action == LAST || action == NOW || mPlayPos + 1 == mPlayListLen
//                addToPlayList(list, Integer.MAX_VALUE);
//                notifyChange(QUEUE_CHANGED);
//                if (action == NOW) {
//                    mPlayPos = mPlayListLen - list.length;
//                    openCurrentAndNext();
//                    play();
//                    notifyChange(META_CHANGED);
//                    return;
//                }
//            }
//            if (mPlayPos < 0) {
//                mPlayPos = 0;
//                openCurrentAndNext();
//                play();
//                notifyChange(META_CHANGED);
//            }
//        }
//    }
//
//    /**
//     * Replaces the current playlist with a new list,
//     * and prepares for starting playback at the specified
//     * position in the list, or a random position if the
//     * specified position is 0.
//     *
//     * @param list The new list of tracks.
//     */
//    public void open(long[] list, int position) {
//        synchronized (this) {
//            if (mShuffleMode == SHUFFLE_AUTO) {
//                mShuffleMode = SHUFFLE_NORMAL;
//            }
//            long oldId = getAudioId();
//            int listlength = list.length;
//            boolean newlist = true;
//            if (mPlayListLen == listlength) {
//                // possible fast path: list might be the same
//                newlist = false;
//                for (int i = 0; i < listlength; i++) {
//                    if (list[i] != mPlayList[i]) {
//                        newlist = true;
//                        break;
//                    }
//                }
//            }
//            if (newlist) {
//                addToPlayList(list, -1);
//                notifyChange(QUEUE_CHANGED);
//            }
//            int oldpos = mPlayPos;
//            if (position >= 0) {
//                mPlayPos = position;
//            } else {
//                mPlayPos = mRand.nextInt(mPlayListLen);
//            }
//            mHistory.clear();
//
//            saveBookmarkIfNeeded();
//            openCurrentAndNext();
//            if (oldId != getAudioId()) {
//                notifyChange(META_CHANGED);
//            }
//        }
//    }
//
//    /**
//     * Moves the item at index1 to index2.
//     *
//     * @param index1
//     * @param index2
//     */
//    public void moveQueueItem(int index1, int index2) {
//        synchronized (this) {
//            if (index1 >= mPlayListLen) {
//                index1 = mPlayListLen - 1;
//            }
//            if (index2 >= mPlayListLen) {
//                index2 = mPlayListLen - 1;
//            }
//            if (index1 < index2) {
//                long tmp = mPlayList[index1];
//                for (int i = index1; i < index2; i++) {
//                    mPlayList[i] = mPlayList[i + 1];
//                }
//                mPlayList[index2] = tmp;
//                if (mPlayPos == index1) {
//                    mPlayPos = index2;
//                } else if (mPlayPos >= index1 && mPlayPos <= index2) {
//                    mPlayPos--;
//                }
//            } else if (index2 < index1) {
//                long tmp = mPlayList[index1];
//                for (int i = index1; i > index2; i--) {
//                    mPlayList[i] = mPlayList[i - 1];
//                }
//                mPlayList[index2] = tmp;
//                if (mPlayPos == index1) {
//                    mPlayPos = index2;
//                } else if (mPlayPos >= index2 && mPlayPos <= index1) {
//                    mPlayPos++;
//                }
//            }
//            notifyChange(QUEUE_CHANGED);
//        }
//    }
//
//    /**
//     * Returns the current play list
//     *
//     * @return An array of integers containing the IDs of the tracks in the play list
//     */
//    public long[] getQueue() {
//        synchronized (this) {
//            int len = mPlayListLen;
//            long[] list = new long[len];
//            for (int i = 0; i < len; i++) {
//                list[i] = mPlayList[i];
//            }
//            return list;
//        }
//    }
//
//    private Cursor getCursorForId(long lid) {
//        String id = String.valueOf(lid);
//
//        Cursor c = getContentResolver().query(
//                MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
//                mCursorCols, "_id=" + id, null, null);
//        if (c != null) {
//            c.moveToFirst();
//        }
//        return c;
//    }
//
//    private void openCurrentAndNext() {
//        synchronized (this) {
//            if (mCursor != null) {
//                mCursor.close();
//                mCursor = null;
//            }
//
//            if (mPlayListLen == 0) {
//                return;
//            }
//            stop(false);
//
//            mCursor = getCursorForId(mPlayList[mPlayPos]);
//            while (true) {
//                if (mCursor != null && mCursor.getCount() != 0 &&
//                        open(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "/" +
//                                mCursor.getLong(IDCOLIDX))) {
//                    break;
//                }
//                // if we get here then opening the file failed. We can close the cursor now, because
//                // we're either going to create a new one next, or stop trying
//                if (mCursor != null) {
//                    mCursor.close();
//                    mCursor = null;
//                }
//                if (mOpenFailedCounter++ < 10 && mPlayListLen > 1) {
//                    int pos = getNextPosition(false);
//                    if (pos < 0) {
//                        gotoIdleState();
//                        if (mIsSupposedToBePlaying) {
//                            mIsSupposedToBePlaying = false;
//                            notifyChange(PLAYSTATE_CHANGED);
//                        }
//                        return;
//                    }
//                    mPlayPos = pos;
//                    stop(false);
//                    mPlayPos = pos;
//                    mCursor = getCursorForId(mPlayList[mPlayPos]);
//                } else {
//                    mOpenFailedCounter = 0;
//                    if (!mQuietMode) {
//                        Toast.makeText(this, R.string.playback_failed, Toast.LENGTH_SHORT).show();
//                    }
//                    Log.d(LOGTAG, "Failed to open file for playback");
//                    gotoIdleState();
//                    if (mIsSupposedToBePlaying) {
//                        mIsSupposedToBePlaying = false;
//                        notifyChange(PLAYSTATE_CHANGED);
//                    }
//                    return;
//                }
//            }
//
//            // go to bookmark if needed
//            if (isPodcast()) {
//                long bookmark = getBookmark();
//                // Start playing a little bit before the bookmark,
//                // so it's easier to get back in to the narrative.
//                seek(bookmark - 5000);
//            }
//            setNextTrack();
//        }
//    }
//
//    private void setNextTrack() {
//        mNextPlayPos = getNextPosition(false);
//        if (mNextPlayPos >= 0) {
//            long id = mPlayList[mNextPlayPos];
//            mPlayer.setNextDataSource(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "/" + id);
//        }
//    }
//
//    /**
//     * Opens the specified file and readies it for playback.
//     *
//     * @param path The full path of the file to be opened.
//     */
//    public boolean open(String path) {
//        synchronized (this) {
//            if (path == null) {
//                return false;
//            }
//
//            // if mCursor is null, try to associate path with a database cursor
//            if (mCursor == null) {
//
//                ContentResolver resolver = getContentResolver();
//                Uri uri;
//                String where;
//                String selectionArgs[];
//                if (path.startsWith("content://media/")) {
//                    uri = Uri.parse(path);
//                    where = null;
//                    selectionArgs = null;
//                } else {
//                    uri = MediaStore.Audio.Media.getContentUriForPath(path);
//                    where = MediaStore.Audio.Media.DATA + "=?";
//                    selectionArgs = new String[]{path};
//                }
//
//                try {
//                    mCursor = resolver.query(uri, mCursorCols, where, selectionArgs, null);
//                    if (mCursor != null) {
//                        if (mCursor.getCount() == 0) {
//                            mCursor.close();
//                            mCursor = null;
//                        } else {
//                            mCursor.moveToNext();
//                            ensurePlayListCapacity(1);
//                            mPlayListLen = 1;
//                            mPlayList[0] = mCursor.getLong(IDCOLIDX);
//                            mPlayPos = 0;
//                        }
//                    }
//                } catch (UnsupportedOperationException ex) {
//                }
//            }
//            mFileToPlay = path;
//            mPlayer.setDataSource(mFileToPlay);
//            if (mPlayer.isInitialized()) {
//                mOpenFailedCounter = 0;
//                return true;
//            }
//            stop(true);
//            return false;
//        }
//    }
//
//    /**
//     * Starts playback of a previously opened file.
//     */
//    public void play() {
//        mAudioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC,
//                AudioManager.AUDIOFOCUS_GAIN);
//        mAudioManager.registerMediaButtonEventReceiver(new ComponentName(this.getPackageName(),
//                MediaButtonIntentReceiver.class.getName()));
//
//        if (mPlayer.isInitialized()) {
//            // if we are at the end of the song, go to the next song first
//            long duration = mPlayer.duration();
//            if (mRepeatMode != REPEAT_CURRENT && duration > 2000 &&
//                    mPlayer.position() >= duration - 2000) {
//                gotoNext(true);
//            }
//
//            mPlayer.start();
//            // make sure we fade in, in case a previous fadein was stopped because
//            // of another focus loss
//            mMediaplayerHandler.removeMessages(FADEDOWN);
//            mMediaplayerHandler.sendEmptyMessage(FADEUP);
//
//            updateNotification();
//            if (!mIsSupposedToBePlaying) {
//                mIsSupposedToBePlaying = true;
//                notifyChange(PLAYSTATE_CHANGED);
//            }
//
//        } else if (mPlayListLen <= 0) {
//            // This is mostly so that if you press 'play' on a bluetooth headset
//            // without every having played anything before, it will still play
//            // something.
//            setShuffleMode(SHUFFLE_AUTO);
//        }
//    }
//
//    private void updateNotification() {
//        RemoteViews views = new RemoteViews(getPackageName(), R.layout.statusbar);
//        views.setImageViewResource(R.id.icon, R.drawable.stat_notify_musicplayer);
//        if (getAudioId() < 0) {
//            // streaming
//            views.setTextViewText(R.id.trackname, getPath());
//            views.setTextViewText(R.id.artistalbum, null);
//        } else {
//            String artist = getArtistName();
//            views.setTextViewText(R.id.trackname, getTrackName());
//            if (artist == null || artist.equals(MediaStore.UNKNOWN_STRING)) {
//                artist = getString(R.string.unknown_artist_name);
//            }
//            String album = getAlbumName();
//            if (album == null || album.equals(MediaStore.UNKNOWN_STRING)) {
//                album = getString(R.string.unknown_album_name);
//            }
//
//            views.setTextViewText(R.id.artistalbum,
//                    getString(R.string.notification_artist_album, artist, album)
//            );
//        }
//        Notification status = new Notification();
//        status.contentView = views;
//        status.flags |= Notification.FLAG_ONGOING_EVENT;
//        status.icon = R.drawable.stat_notify_musicplayer;
//        status.contentIntent = PendingIntent.getActivity(this, 0,
//                new Intent("com.android.music.PLAYBACK_VIEWER")
//                        .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0);
//        startForeground(PLAYBACKSERVICE_STATUS, status);
//    }
//
//    private void stop(boolean remove_status_icon) {
//        if (mPlayer.isInitialized()) {
//            mPlayer.stop();
//        }
//        mFileToPlay = null;
//        if (mCursor != null) {
//            mCursor.close();
//            mCursor = null;
//        }
//        if (remove_status_icon) {
//            gotoIdleState();
//        } else {
//            stopForeground(false);
//        }
//        if (remove_status_icon) {
//            mIsSupposedToBePlaying = false;
//        }
//    }
//
//    /**
//     * Stops playback.
//     */
//    public void stop() {
//        stop(true);
//    }
//
//    /**
//     * Pauses playback (call play() to resume)
//     */
//    public void pause() {
//        synchronized (this) {
//            mMediaplayerHandler.removeMessages(FADEUP);
//            if (isPlaying()) {
//                mPlayer.pause();
//                gotoIdleState();
//                mIsSupposedToBePlaying = false;
//                notifyChange(PLAYSTATE_CHANGED);
//                saveBookmarkIfNeeded();
//            }
//        }
//    }
//
//    /**
//     * Returns whether something is currently playing
//     *
//     * @return true if something is playing (or will be playing shortly, in case
//     * we're currently transitioning between tracks), false if not.
//     */
//    public boolean isPlaying() {
//        return mIsSupposedToBePlaying;
//    }
//
//    /*
//      Desired behavior for prev/next/shuffle:
//
//      - NEXT will move to the next track in the list when not shuffling, and to
//        a track randomly picked from the not-yet-played tracks when shuffling.
//        If all tracks have already been played, pick from the full set, but
//        avoid picking the previously played track if possible.
//      - when shuffling, PREV will go to the previously played track. Hitting PREV
//        again will go to the track played before that, etc. When the start of the
//        history has been reached, PREV is a no-op.
//        When not shuffling, PREV will go to the sequentially previous track (the
//        difference with the shuffle-case is mainly that when not shuffling, the
//        user can back up to tracks that are not in the history).
//
//        Example:
//        When playing an album with 10 tracks from the start, and enabling shuffle
//        while playing track 5, the remaining tracks (6-10) will be shuffled, e.g.
//        the final play order might be 1-2-3-4-5-8-10-6-9-7.
//        When hitting 'prev' 8 times while playing track 7 in this example, the
//        user will go to tracks 9-6-10-8-5-4-3-2. If the user then hits 'next',
//        a random track will be picked again. If at any time user disables shuffling
//        the next/previous track will be picked in sequential order again.
//     */
//
//    public void prev() {
//        synchronized (this) {
//            if (mShuffleMode == SHUFFLE_NORMAL) {
//                // go to previously-played track and remove it from the history
//                int histsize = mHistory.size();
//                if (histsize == 0) {
//                    // prev is a no-op
//                    return;
//                }
//                Integer pos = mHistory.remove(histsize - 1);
//                mPlayPos = pos.intValue();
//            } else {
//                if (mPlayPos > 0) {
//                    mPlayPos--;
//                } else {
//                    mPlayPos = mPlayListLen - 1;
//                }
//            }
//            saveBookmarkIfNeeded();
//            stop(false);
//            openCurrentAndNext();
//            play();
//            notifyChange(META_CHANGED);
//        }
//    }
//
//    /**
//     * Get the next position to play. Note that this may actually modify mPlayPos
//     * if playback is in SHUFFLE_AUTO mode and the shuffle list window needed to
//     * be adjusted. Either way, the return value is the next value that should be
//     * assigned to mPlayPos;
//     */
//    private int getNextPosition(boolean force) {
//        if (mRepeatMode == REPEAT_CURRENT) {
//            if (mPlayPos < 0) return 0;
//            return mPlayPos;
//        } else if (mShuffleMode == SHUFFLE_NORMAL) {
//            // Pick random next track from the not-yet-played ones
//            // TODO: make it work right after adding/removing items in the queue.
//
//            // Store the current file in the history, but keep the history at a
//            // reasonable size
//            if (mPlayPos >= 0) {
//                mHistory.add(mPlayPos);
//            }
//            if (mHistory.size() > MAX_HISTORY_SIZE) {
//                mHistory.removeElementAt(0);
//            }
//
//            int numTracks = mPlayListLen;
//            int[] tracks = new int[numTracks];
//            for (int i = 0; i < numTracks; i++) {
//                tracks[i] = i;
//            }
//
//            int numHistory = mHistory.size();
//            int numUnplayed = numTracks;
//            for (int i = 0; i < numHistory; i++) {
//                int idx = mHistory.get(i).intValue();
//                if (idx < numTracks && tracks[idx] >= 0) {
//                    numUnplayed--;
//                    tracks[idx] = -1;
//                }
//            }
//
//            // 'numUnplayed' now indicates how many tracks have not yet
//            // been played, and 'tracks' contains the indices of those
//            // tracks.
//            if (numUnplayed <= 0) {
//                // everything's already been played
//                if (mRepeatMode == REPEAT_ALL || force) {
//